import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { GqlExecutionContext } from '@nestjs/graphql';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class GqlRolesGuard extends AuthGuard('jwt') {
    constructor(private readonly reflector: Reflector) {
        super();
    }

    getRequest(context: ExecutionContext) {
        const ctx = GqlExecutionContext.create(context);
        return ctx.getContext().req;
    }

    async canActivate(context: ExecutionContext): Promise<boolean> {
        try {
            if (!await super.canActivate(context)) return false;
        } catch (err) {
            throw err;
        }

        // 获取roles元数据，roles与roles.decorator.ts中SetMetadata()第一个参数一致
        const roles = this.reflector.get<string[]>('roles', context.getHandler());
        if (!roles) { // 未被装饰器装饰，直接放行
            return true;
        }
        const req = this.getRequest(context);
        const user = req.user;
        const hasRole = () => user.roles.some((role) => roles.includes(role));
        return user && user.roles && hasRole();
    }
}